package com.extra_archive.project.iisu.view.detail.tapdance 
{
	import Box2D.Collision.Shapes.b2MassData;
	import Box2D.Collision.Shapes.b2PolygonDef;
	import Box2D.Collision.b2AABB;
	import Box2D.Common.Math.b2Vec2;
	import Box2D.Dynamics.b2Body;
	import Box2D.Dynamics.b2BodyDef;
	import Box2D.Dynamics.b2DebugDraw;
	import Box2D.Dynamics.b2World;

	import com.extra_archive.framework.core.mvc.controller.IController;
	import com.extra_archive.framework.core.mvc.model.IModel;
	import com.extra_archive.framework.core.mvc.view.CompositeView;
	import com.extra_archive.framework.utils.NumberUtils;
	import com.extra_archive.project.iisu.model.ARModel;

	import flash.display.DisplayObject;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.events.KeyboardEvent;

	// @class Name :	BasicPhysicView.as
	// @author : 		d.mind (min hyuk,lim) (http://www.dmindproject.com)
	// @last update : 	2010. 5. 4.
	// @version :		v1.0
	// @description : 

	public class TapdanceView extends CompositeView 
	{
		private var _world : b2World;

		private var _physicScale : Number = 30.0;

		private var _timeStep : Number = 1.0 / 30.0;

		private var _iteration : Number = 10.0;

		private var _viewportWidth : uint;
		private var _viewportHeight : uint;

		private var _debugView : Sprite;

		private var _numberClipCount : int;
		private var _alphabetClipCount : int;
		private var _waterClipCount : int;

		
		
		
		public function TapdanceView(model : IModel, controller : IController = null)
		{
			super(model, controller);
			
			_viewportWidth = _model.applicationContainer.stage.stageWidth;
			_viewportHeight = _model.applicationContainer.stage.stageHeight;
			
			createWorld();
			createDebug();

			addEventListener(Event.ADDED_TO_STAGE, addedToStage, false, 0, true);
		}

		//--------------------------------------------------------------------------------------------
		//
		//								public function          
		//         
		//--------------------------------------------------------------------------------------------
		/**
		 * 렌더링 시작
		 */
		public function startRendering() : void
		{
			if(!hasEventListener(Event.ENTER_FRAME))
				addEventListener(Event.ENTER_FRAME, render);
		}

		
		/**
		 * 렌더링 정지
		 */	
		public function stopRendering() : void
		{
			if(hasEventListener(Event.ENTER_FRAME))
				removeEventListener(Event.ENTER_FRAME, render);
		}

		public function destroy() : void
		{
			while(this.numChildren > 0)
			{
				var obj : * = this.removeChildAt(0);
				obj = null;	
			}	
			for(var bb : b2Body = _world.GetBodyList();bb;bb = bb.GetNext())
			{
				_world.DestroyBody(bb);
				bb = null;	
			}
		}

		//--------------------------------------------------------------------------------------------
		//
		//								event listener
		//         
		//--------------------------------------------------------------------------------------------
		
		private function addedToStage(event : Event) : void
		{
			removeEventListener(Event.ADDED_TO_STAGE, addedToStage);
			stage.addEventListener(KeyboardEvent.KEY_DOWN, keyDownHandler);
		}

		private function keyDownHandler(event : KeyboardEvent) : void
		{
			switch(String.fromCharCode(event.charCode))
			{
				case "h":
					if(contains(_debugView))
						removeChild(_debugView);
					else
						addChild(_debugView);
					break;
			}
		}

		private function render(event : Event) : void
		{
			try
			{
				for(var bb : b2Body = _world.GetBodyList();bb;bb = bb.GetNext())
				{
					var sprite : Sprite = bb.GetUserData() as Sprite;
					if(sprite)
					{
						if(Math.round(bb.GetPosition().y * _physicScale) - sprite.y < 0) UserClip(sprite).direction = "down"; 
						sprite.x = Math.round(bb.GetPosition().x * _physicScale);
						sprite.y = Math.round(bb.GetPosition().y * _physicScale);
						sprite.rotation += 2;
					
						if(UserClip(sprite).direction == "down")
						{
							if(sprite.y > _viewportHeight)
							{
								destoryUserClip(sprite as UserClip, bb);
							}	
						}	
					}
				}
			}
			catch(e : Error)
			{
			}
				
			_world.Step(_timeStep, _iteration);
		}

		//--------------------------------------------------------------------------
		//
		//    Private Methods
		//
		//--------------------------------------------------------------------------
		
		private function destoryUserClip(clip : UserClip, body : b2Body) : void
		{
			try
			{
				if(!clip.live) return;
				switch(clip.type)
				{
					case ClipType.NUMBER_CLIP:
						_numberClipCount--;
						break;
					
					case ClipType.ALPHABET_CLIP:
						_alphabetClipCount--;
						break;
					
					case ClipType.WATER_CLIP:
						_waterClipCount--;
						break;	
				}
				
				clip.destroy();
				clip.live = false;
				_world.DestroyBody(body);
				body = null;
				
				removeChild(clip as DisplayObject);
				clip = null;
			}
			catch(e : Error)
			{
				trace(e);
			}
		}		

		
		private function createDynamicObject(type : String, x : int, y : int, w : uint, h : uint, force : Number = 0) : void
		{
			if(type == ClipType.NUMBER_CLIP && _numberClipCount > 3) return;
			if(type == ClipType.ALPHABET_CLIP && _alphabetClipCount > 4) return;
			
			var bodyX : int = x + NumberUtils.randomIntInRange(-50, 50);
			
			var bodyDef : b2BodyDef = new b2BodyDef();
			bodyDef.position.Set(bodyX / _physicScale, y / _physicScale);
			bodyDef.angle = NumberUtils.randomIntInRange(0, 360);
			bodyDef.userData = new UserClip();
			bodyDef.userData["width"] = w;
			bodyDef.userData["height"] = h;
			bodyDef.userData["direction"] = "up";
			bodyDef.userData["type"] = type;
			addChild(bodyDef.userData);
			
			
			switch(type)
			{
				case ClipType.NUMBER_CLIP:
					_numberClipCount++;
					break;
					
				case ClipType.ALPHABET_CLIP:
					_alphabetClipCount++;
					break;
					
				case ClipType.WATER_CLIP:
					_waterClipCount++;
					break;	
			}			
			
			var boxDef : b2PolygonDef = new b2PolygonDef();
			boxDef.SetAsBox(w / _physicScale / 2, h / _physicScale / 2);
			boxDef.density = w / _physicScale / 2;
			boxDef.isSensor = true;
			
			var body : b2Body = _world.CreateBody(bodyDef);
			body.CreateShape(boxDef);
			body.SetMassFromShapes();
			
			var massData : b2MassData = new b2MassData();
			massData.mass = 0.01;
			body.SetMass(massData);
			
			var forceX : Number = NumberUtils.randomIntInRange(-1, 1) / _physicScale; 
			var forceY : Number = -(2 + (NumberUtils.randomIntInRange(2, 5) * force / 100)) / _physicScale;
			body.ApplyImpulse(new b2Vec2(forceX, forceY), body.GetWorldCenter());
		}

		
		private function createDebug() : void
		{
			_debugView = new Sprite();
			_debugView.graphics.lineStyle(1, 0xff0000);
			_debugView.graphics.drawRect(0, 0, _viewportWidth - 1, _viewportHeight - 1);
			_debugView.graphics.endFill();
			
			var dbgDraw : b2DebugDraw = new b2DebugDraw();
			dbgDraw.m_sprite = new Sprite();
			dbgDraw.m_drawScale = _physicScale;
			dbgDraw.m_fillAlpha = 0.3;
			dbgDraw.m_lineThickness = 1;
			dbgDraw.m_drawFlags = b2DebugDraw.e_shapeBit | b2DebugDraw.e_jointBit;
			_world.SetDebugDraw(dbgDraw);
			_debugView.addChild(dbgDraw.m_sprite);
		}

		private function createWorld() : void
		{
			var aabbValue : Number = _viewportWidth / _physicScale;
			var worldAABB : b2AABB = new b2AABB();
			worldAABB.lowerBound.Set(-aabbValue, -aabbValue);
			worldAABB.upperBound.Set(aabbValue, aabbValue);
			
			var gravity : b2Vec2 = new b2Vec2(0, 50);
			var doSleep : Boolean = true;
			_world = new b2World(worldAABB, gravity, doSleep);
		}
	}
}

import com.extra_archive.project.iisu.model.detail.factory.ImageClipFactory;

import flash.display.Sprite;

class UserClip extends Sprite
{
	public var direction : String = "stop";	// stop, up, down

	public var type : String;

	public var live : Boolean = true;

	public function UserClip()
	{
		addChild(ImageClipFactory.getInstance().next());
	} 

	public function destroy() : void
	{
	}
}
